﻿/* This Software is Licenced under MIT Licence (http://en.wikipedia.org/wiki/MIT_License)

Copyright (c) 2012 Andrea Cappelletti, Milan, Italy aka CleverWalrus)

Permission is hereby granted, free of charge, to any person obtaining a copy of this 
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge, 
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons 
to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies 
or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
DEALINGS IN THE SOFTWARE.*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using UnityEngine;

using CleverBobCat.Core;

namespace CleverBobCat.EngineController
{
    public class ModuleCleverEngineController : PartModule
    {
        [KSPField]
        public bool debug = false;

        [KSPField]
        public float winPosX = 0;

        [KSPField]
        public float winPosY = 0;

        private Rect winPos;
        float defaultGUIWidth = 10;
        float defaultGUIHeight = 10;
        bool guiInitialized = false;

        private bool initialized = false;
        private int lastStage;

        // Store all current engine groups
        private List<CleverEngineGroup> engineGroups;

        /// <summary>
        /// Constructor style setup.
        /// Called in the Part\'s Awake method. 
        /// The model may not be built by this point.
        /// </summary>
        public override void OnAwake()
        {
        }

        /// <summary>
        /// Called during the Part startup.
        /// StartState gives flag values of initial state
        /// </summary>
        public override void OnStart(StartState state)
        {
            UpdateEngineGroups();
            initialized = true;
            lastStage = Staging.CurrentStage;  
        }

        /// <summary>
        /// Per-frame update
        /// Called ONLY when Part is ACTIVE!
        /// </summary>
        public override void OnUpdate()
        {
            if (part.isControllable && vessel == FlightGlobals.ActiveVessel && InputLockManager.IsUnlocked(ControlTypes.THROTTLE))
            {
                if (!guiInitialized)
                {
                    RenderingManager.AddToPostDrawQueue(3, new Callback(drawGUI));
                    part.OnJustAboutToBeDestroyed += CleanUpGUI;
                    guiInitialized = true;
                }
                if (Staging.CurrentStage != lastStage)
                {
                    UpdateEngineGroups();
                    winPos.height = defaultGUIHeight;
                    lastStage = Staging.CurrentStage;
                }
            }
        }

        /// <summary>
        /// Per-physx-frame update
        /// Called ONLY when Part is ACTIVE!
        /// </summary>
        public override void OnFixedUpdate()
        {
        }

        /// <summary>
        /// Called when PartModule is asked to save its values.
        /// Can save additional data here.
        /// </summary>
        /// <param name='node'>The node to save in to</param>
        public override void OnSave(ConfigNode node)
        {
        }

        /// <summary>
        /// Called when PartModule is asked to load its values.
        /// Can load additional data here.
        /// </summary>
        /// <param name='node'>The node to load from</param>
        public override void OnLoad(ConfigNode node)
        {
        }

        public void CleanUpGUI()
        {
            RenderingManager.RemoveFromPostDrawQueue(3, new Callback(drawGUI));
        }

        /// <summary>
        /// Called at initialization and every staging for retrieving all
        /// the engine groups currently available.
        /// </summary>
        [KSPEvent]
        public void UpdateEngineGroups()
        {
            engineGroups = new List<CleverEngineGroup>();
            Logger.Debug(debug, "UpdateEngineGroups()");
            foreach (Part p in vessel.parts)
            {
                if (p.Modules.Contains("ModuleCleverLiquidEngine") || p.Modules.Contains("ModuleCleverAtmosphericEngine") || p.Modules.Contains("ModuleCleverRCSModule"))
                {
                    try
                    {
                        PartModule CleverEngine = new PartModule();
                        if (p.Modules.Contains("ModuleCleverLiquidEngine"))
                        {
                            CleverEngine = p.Modules["ModuleCleverLiquidEngine"];
                            Logger.Debug(debug, "Found", "ModuleCleverLiquidEngine");
                        }
                        else if (p.Modules.Contains("ModuleCleverAtmosphericEngine"))
                        {
                            CleverEngine = p.Modules["ModuleCleverAtmosphericEngine"];
                            Logger.Debug(debug, "Found", "ModuleCleverAtmosphericEngine");
                        }
                        else if (p.Modules.Contains("ModuleCleverRCSModule"))
                        {
                            CleverEngine = p.Modules["ModuleCleverRCSModule"];
                            Logger.Debug(debug, "Found", "ModuleCleverRCSModule");
                        }

                        string engineGroupName = (string)ModuleUtils.GetFieldValue(CleverEngine, "engineGroup");
                        if (engineGroups.FirstOrDefault(x => x.name == engineGroupName) == null)
                        {
                            CleverEngineGroup newEngineGroup = new CleverEngineGroup();
                            newEngineGroup.name = (string)ModuleUtils.GetFieldValue(CleverEngine, "engineGroup");
                            newEngineGroup.active = (bool)ModuleUtils.GetFieldValue(CleverEngine, "engineActive");
                            newEngineGroup.throttle = (float)ModuleUtils.GetFieldValue(CleverEngine, "engineThrottle");
                            engineGroups.Add(newEngineGroup);
                            Logger.Debug(debug, "NewEngineGroup", engineGroupName);
                        }
                    }
                    catch (Exception ex)
                    {
                        Logger.Error(ex.Message);
                    }
                }
            }
        }

        private void WindowGUI(int windowID)
        {
            GUILayout.BeginVertical();
            foreach (CleverEngineGroup engineGroup in engineGroups)
            {
                engineGroup.active = GUILayout.Toggle(engineGroup.active, engineGroup.name);
                engineGroup.throttle = GUILayout.HorizontalSlider(engineGroup.throttle, 0F, 100F);

                if (engineGroup.lastActive != engineGroup.active || engineGroup.throttle != engineGroup.lastThrottle)
                {
                    if (engineGroup.active)
                    {
                        BaseEventData data = new BaseEventData(BaseEventData.Sender.USER);
                        data.Set("engineGroup", engineGroup);
                        part.SendEvent("UpdateEngineGroup", data);
                    }
                    else
                    {
                        BaseEventData data = new BaseEventData(BaseEventData.Sender.USER);
                        data.Set("engineGroup", engineGroup);
                        part.SendEvent("UpdateEngineGroup", data);
                    }
                }

                engineGroup.lastActive = engineGroup.active;
                engineGroup.lastThrottle = engineGroup.throttle;
            }
            GUILayout.EndVertical();
            GUI.DragWindow();
        }

        private void drawGUI()
        {
            if (part.isControllable && vessel == FlightGlobals.ActiveVessel && initialized && engineGroups.Count > 0 && InputLockManager.IsUnlocked(ControlTypes.THROTTLE))
            {
                if (winPos.x == 0 && winPos.y == 0)
                {
                    if (winPosX == 0 && winPosY == 0)
                    {
                        winPosX = Screen.width / 2;
                        winPosY = Screen.height / 2;
                        winPos = new Rect(winPosX, winPosY, defaultGUIWidth, defaultGUIHeight);
                    }
                    else
                    {
                        winPos = new Rect(winPosX, winPosY, defaultGUIWidth, defaultGUIHeight);
                    }

                }
                else
                {
                    winPosX = winPos.x;
                    winPosY = winPos.y;
                }
                GUI.skin = HighLogic.Skin;
                winPos = GUILayout.Window(123, winPos, WindowGUI, "Engine Control", GUILayout.MinWidth(150));
            }
        }
    }
}
